﻿using Ec.NETCoreFramework.Common.Core;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Quartz;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Loader;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Ec.NETCoreFramework.Common.Plug.QuartzService
{
    public class QuartzHostedService : BackgroundService
    {
        private readonly ISchedulerFactory _schedulerFactory;
        private readonly ILogger<QuartzHostedService> _logger;
        public QuartzHostedService(ILogger<QuartzHostedService> logger,
            ISchedulerFactory schedulerFactory)
        {
            _logger = logger;
            _schedulerFactory = schedulerFactory;
        }
        public IScheduler Scheduler { get; set; }

        public override async Task StartAsync(CancellationToken cancellationToken)
        {
            Scheduler = await _schedulerFactory.GetScheduler(cancellationToken);

            //定时任务
            var jobs = new List<JobBase>();
            var path = Path.Combine(Directory.GetCurrentDirectory(), "plandll");
            // dll 必须要是JOB_
            var fileInfos = Directory.GetFiles(path).Where(f => f.Contains("Job_")).ToArray();
            // 通过stream的方式,加载dll ,防止,后面dll删除不了,dll被用了,
            var _AssemblyLoadContext = new AssemblyLoadContext(Guid.NewGuid().ToString("N"), true);

           
            foreach (var item in fileInfos)
            {
                JobBase currentJob;
                using (var fs = new FileStream(item, FileMode.Open, FileAccess.Read))
                {
                    var assembly = _AssemblyLoadContext.LoadFromStream(fs);//可以直接读数据库																		  
                    var type = assembly.GetExportedTypes().Where(t => t.GetInterfaces().Contains(typeof(IJob))).FirstOrDefault();

                    currentJob = Activator.CreateInstance(type) as JobBase;
                }
                var fileInfo = new FileInfo(item);

                currentJob.FileInfoLastTime = fileInfo.LastWriteTime;
              

                // 添加任务  
                var jobmodel = currentJob.InitJobModel();
                if (jobmodel == null) continue;
                var job = CreateJob(currentJob);
                job.JobDataMap.Add("data", jobmodel.Data);
                var trigger = CreateTrigger(jobmodel);

                await Scheduler.ScheduleJob(job, trigger, cancellationToken);
            }
            await Scheduler.Start(cancellationToken);
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                
                await Task.Delay(1000, stoppingToken);
            }
        }
        public override async Task StopAsync(CancellationToken cancellationToken)
        {
            await Scheduler?.Shutdown(cancellationToken);
        }

        public static IJobDetail CreateJob(JobBase schedule)
        {
            var jobType = schedule.GetType();
            return JobBuilder
                .Create(jobType)
                .WithIdentity(jobType.FullName)
                .WithDescription(jobType.Name)
                .Build();
        }

        private static ITrigger CreateTrigger(JobDto schedule)
        {
            return TriggerBuilder
                .Create()
                .WithIdentity(schedule.Name, schedule.GroupName)
                .WithCronSchedule(schedule.CronSchedule)
                .WithDescription(schedule.Description)
                .Build();
        }
    }
}
